use crate::sink::{Sink, SinkResult, SinkData};
use crate::conf_init::{MapResult};

use tokio::fs::*;
use tokio::io::AsyncWriteExt;
use tokio::runtime::Runtime;


#[derive(Deserialize,Debug)]
pub struct FileConf{
    file: String
}

#[derive(Debug)]
pub struct FileOut{
    file: String,
    file_handle: Option<File>,
}

impl FileOut{
    pub fn new(conf: &FileConf)->MapResult<Box<dyn Sink>>{
        MapResult::Ok(Box::new(
            FileOut{
                file:conf.file.to_string(),
                file_handle: None,
            }
        ))
    }
}

#[async_trait]
impl Sink for FileOut{
    async fn init(&mut self)->bool{
        let mut options = OpenOptions::new();

        if let Ok(file_handle) = options
            .create(true)
            .append(true)
            .open(self.file.to_string()).await{
            self.file_handle = Some(file_handle);
            return true;
        }else{
            self.file_handle = None;
            return false;
        }
    }
    async fn store(&mut self, runtime: &Runtime, data: Vec<Vec<SinkData>>, _burst: usize, _concurrent: usize)->SinkResult{

        if let Some(ref mut file_handle) = self.file_handle{
            for data in data.into_iter() {
                for data in data.into_iter() {
                    if let Err(_err) = file_handle.write(data.data.serialize().as_bytes()).await {
                        return SinkResult::Err(());
                    }
                    if let Err(err) = file_handle.write("\n".as_bytes()).await {
                        return SinkResult::Err(());
                    }
                }
            }

            return SinkResult::Ok(());
        }else{
            return SinkResult::Err(());
        }
    }
}